package com.atguigu.gmall.cart.service.impl;

import com.atguigu.gmall.cart.service.CartService;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.util.DateUtil;
import com.atguigu.gmall.model.cart.CartInfo;
import com.atguigu.gmall.model.product.SkuInfo;
import com.atguigu.gmall.product.client.ProductFeignClient;
import io.swagger.models.auth.In;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class CartServiceImpl implements CartService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private ProductFeignClient productFeignClient;

    @Override
    public List<CartInfo> getCartCheckedList(String userId) {
        //  获取选中的购物车列表. 购物车在缓存中存储.  key  = user:2:cart;
        //  获取购物车的key
        String cartKey = this.getCartKey(userId);
        //  获取列表.  hvals key
        List<CartInfo> cartInfoList = this.redisTemplate.opsForHash().values(cartKey);
        // List values1 = this.redisTemplate.boundHashOps(cartKey).values();
        //        List<CartInfo> cartInfoCheckedList = new ArrayList<>();
        //        //  循环遍历集合找出选中的商品。
        //        for (CartInfo cartInfo : cartInfoList) {
        //            //  选中商品.
        //            if (cartInfo.getIsChecked().intValue()==1){
        //                cartInfoCheckedList.add(cartInfo);
        //            }
        //        }
        //  符合条件的数据留下;
        List<CartInfo> cartInfoCheckedList = cartInfoList.stream().filter((cartInfo) -> {
            //  将选中状态为1的数据留下
            return cartInfo.getIsChecked().intValue() == 1;
        }).collect(Collectors.toList());


        return cartInfoCheckedList;
    }

    @Override
    public void deleteCart(String userId, Long skuId) {
        //  hdel key field
        //  先获取购物车的key
        String cartKey = this.getCartKey(userId);

        //  执行删除命令.
        //        Boolean result = this.redisTemplate.boundHashOps(cartKey).hasKey(skuId.toString());
        //        if (result){
        //            this.redisTemplate.boundHashOps(cartKey).delete(skuId.toString());
        //        }
        this.redisTemplate.boundHashOps(cartKey).delete(skuId.toString());

    }

    @Override
    public void checkCart(Long skuId, Integer isChecked, String userId) {
        //  先获取到缓存的key;
        String cartKey = this.getCartKey(userId);
        //  hget key field;
        CartInfo cartInfo = (CartInfo) this.redisTemplate.boundHashOps(cartKey).get(skuId.toString());

        //  hget key field;
        // CartInfo cartInfo = (CartInfo) this.redisTemplate.opsForHash().get(cartKey, skuId.toString());
        if (cartInfo!=null){
            cartInfo.setIsChecked(isChecked);
            //  修改之后的数据放入缓存.
            this.redisTemplate.boundHashOps(cartKey).put(skuId.toString(),cartInfo);
        }
    }

    @Override
    public List<CartInfo> getCartList(String userId, String userTempId) {

        //  声明一个购物车集合对象。
        List<CartInfo> cartInfoNoLoginList = new ArrayList<>();

        //  未登录.
        if (!StringUtils.isEmpty(userTempId)){
            //  获取未登录购物车数据集合.
            String cartKey = this.getCartKey(userTempId);
            //  获取数据 hvals key;
            cartInfoNoLoginList = this.redisTemplate.opsForHash().values(cartKey);
        }

        //  排序未登录购物车集合数据. 1 登录  111 未登录.
        if (!CollectionUtils.isEmpty(cartInfoNoLoginList) && StringUtils.isEmpty(userId)){
            cartInfoNoLoginList.sort((o1,o2)->{
                //  调用时间比较的工具类
                return DateUtil.truncatedCompareTo(o2.getUpdateTime(),o1.getUpdateTime(), Calendar.SECOND);
            });
            //  返回未登录购物车集合数据.
            return cartInfoNoLoginList;
        }
        //---------------以上代码处理未登录数据-------------------------
        //---------------以下代码涉及到登录数据-------------------------
        /*
            合并：
                登录情况下才会涉及到合并.
                    未登录购物车中有数据的情况下：
                        合并购物车
                    未登录购物车中没有数据：不需要合并！

         */
        //  查询购物车列表。
        //  登录，还是未登录。
        if (!StringUtils.isEmpty(userId)){
            //  获取到登录购物车集合数据，先获取到登录购物车数据 key
            String cartKey = this.getCartKey(userId);
            //  根据 cartKey 来获取到登录集合数据.
            //  hget key field;
            //  BoundHashOperations<H, HK, HV> H: 缓存key 的数据类型 ,HK: 表示field 的数据类型，HV： 表示value的数据类型。
            BoundHashOperations<String,String,CartInfo> boundHashOperations = this.redisTemplate.boundHashOps(cartKey);
            //  boundHashOperations.get(); 获取到value的！
            //  在外层的cartKey 中 判断是否有skuId; boundHashOperations.hasKey();

            //  在登录的情况下判断未登录的购物车中有数据。
            /*
            demo:
                登录：
                    17  1
                    18  1   1

                未登录：
                    17  1
                    18  1
                    19  2   111

                 合并：
                    17  2
                    18  2
                    19  2
             */
            if (!CollectionUtils.isEmpty(cartInfoNoLoginList)){
                //  编写合并的业务逻辑。
                cartInfoNoLoginList.stream().forEach(cartInfoNoLogin -> {
                    //  判断：是否有skuId ; 判断登录的skuId 与 未登录的skuId 是否相同。
                    //  判断 field 是否有相同的！
                    if (boundHashOperations.hasKey(cartInfoNoLogin.getSkuId().toString())){
                        //  17 ,18
                        CartInfo cartInfoLogin = boundHashOperations.get(cartInfoNoLogin.getSkuId().toString());
                        //  未登录 --> 登录合并。 数量合并.
                        cartInfoLogin.setSkuNum(cartInfoLogin.getSkuNum()+cartInfoNoLogin.getSkuNum());
                        //  设置更新时间。
                        cartInfoLogin.setUpdateTime(new Date());

                        //  合并的细节： 选中状态：
                        if (cartInfoNoLogin.getIsChecked().intValue()==1 && cartInfoLogin.getIsChecked().intValue()==0){
                            cartInfoLogin.setIsChecked(1);
                        }
                        //  将更新好的对象写入缓存.
                        boundHashOperations.put(cartInfoNoLogin.getSkuId().toString(),cartInfoLogin);

                    }else {
                        //  19
                        cartInfoNoLogin.setUserId(userId);
                        cartInfoNoLogin.setCreateTime(new Date());
                        cartInfoNoLogin.setUpdateTime(new Date());
                        boundHashOperations.put(cartInfoNoLogin.getSkuId().toString(),cartInfoNoLogin);
                    }
                });
            }
            //  删除未登录购物车集合数据;
            this.redisTemplate.delete(this.getCartKey(userTempId));

            //  获取到合并之后的数据.
            //  boundHashOperations.values(); hvals key;
            //  获取的数据 17 ，18 ，19
            List<CartInfo> cartInfoLoginList = boundHashOperations.values();

            //  做排序：
            if (!CollectionUtils.isEmpty(cartInfoLoginList)){
                cartInfoLoginList.sort((o1,o2)->{
                    return DateUtil.truncatedCompareTo(o2.getUpdateTime(),o1.getUpdateTime(), Calendar.SECOND);
                });
            }

            //  返回登录之后的数据
            return cartInfoLoginList;
        }
        //  返回购物车集合。
        return new ArrayList<>();
    }

    @Override
    public void addToCart(Long skuId, String userId, Integer skuNum) {
        /*
        1.  判断要添加的商品在购物车中是否存在。
            true:
                则数量相加
            false:
                则直接加入购物车

        2.  每次添加购物车的时候都会默认选择状态

        3.  保证放入商品的数据价格是最新的

        4.  排序规则.
            苏宁，京东：按照修改时间排序

         */

        //  购物车的key = user:userId:cart  field = skuId  value = cartInfo
        String cartKey = getCartKey(userId);

        //  hget key field
        CartInfo cartInfoExist = (CartInfo) this.redisTemplate.opsForHash().get(cartKey, skuId.toString());

        //  判断
        if (cartInfoExist!=null){
            //  说明当前加入的购物项，在购物车中存在。
            cartInfoExist.setSkuNum(cartInfoExist.getSkuNum()+skuNum);
            //  判断如果选择状态是 1 则不需要赋值， 如果是0 才需要更改.
            if (cartInfoExist.getIsChecked().intValue()==0){
                cartInfoExist.setIsChecked(1);
            }
            //  赋值实时价格数据.    cartPrice 只记录加入时的价格就可以了。 购物车列表显示的时候，显示的是skuPrice。
            cartInfoExist.setSkuPrice(productFeignClient.getSkuPrice(skuId));

            //  重新赋值一下修改时间.
            cartInfoExist.setUpdateTime(new Date());

            //  放入缓存. hset key field value;
            // this.redisTemplate.opsForHash().put(cartKey,skuId.toString(),cartInfoExist);

        }else {
            //  加入购物项不存在的时候，
            cartInfoExist = new CartInfo();
            //  赋值操作。
            SkuInfo skuInfo = this.productFeignClient.getSkuInfo(skuId); // 有可能会从缓存中获取数据.
            cartInfoExist.setSkuId(skuInfo.getId());
            cartInfoExist.setSkuName(skuInfo.getSkuName());
            cartInfoExist.setSkuNum(skuNum);
            //  第一次添加到缓存的时候， 加入购物车的价格 与 实时价格应该一直。
            cartInfoExist.setSkuPrice(this.productFeignClient.getSkuPrice(skuId));
            cartInfoExist.setCartPrice(this.productFeignClient.getSkuPrice(skuId));
            //  可能会价格不一致.
            //            cartInfo.setCartPrice(skuInfo.getPrice());
            //            cartInfo.setSkuPrice(skuInfo.getPrice());
            cartInfoExist.setImgUrl(skuInfo.getSkuDefaultImg());
            cartInfoExist.setUserId(userId);
            cartInfoExist.setCreateTime(new Date());
            cartInfoExist.setUpdateTime(new Date());
            //  放入缓存. hset key field value;
            // this.redisTemplate.opsForHash().put(cartKey,skuId.toString(),cartInfo);
        }

        //  放入缓存. hset key field value;
        this.redisTemplate.opsForHash().put(cartKey,skuId.toString(),cartInfoExist);

        //  暂时不设置购物车的过期时间.
    }

    //  获取购物车key的方法.
    private String getCartKey(String userId) {
        return RedisConst.USER_KEY_PREFIX+userId+RedisConst.USER_CART_KEY_SUFFIX;
    }
}
